package com.example.zyl.common.query.aspect;

import com.example.zyl.common.exception.ServiceException;
import com.example.zyl.common.query.annotation.ApiLock;
import com.example.zyl.common.utils.ToolUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class LockAspect {

    private final RedissonClient redissonClient;

    @Around("@annotation(com.example.zyl.common.query.annotation.ApiLock)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取注解
        ApiLock apiLock = signature.getMethod().getAnnotation(ApiLock.class);
        // 获取锁的key
        String key = apiLock.key().concat(ToolUtils.concatKey(joinPoint.getArgs(), false));
        // 获取锁的超时时间
        long value = apiLock.timeout();
        // 获取锁的超时时间单位
        TimeUnit unit = apiLock.unit();

        // 获取锁
        RLock lock = redissonClient.getLock(key);

        Object result = null;
        try {
            // 阻塞地获取锁，直到成功获取
            lock.lock(value, unit);
            // 执行目标方法
            result = joinPoint.proceed();
        } catch (Throwable throwable) {
            log.error("执行方法出现异常 ====> [{}]", throwable.getMessage());
            throw new ServiceException(throwable.getMessage());
        } finally {
            // 释放锁
            lock.unlock();
        }

        if (result != null) {
            return result;
        }

        throw new ServiceException("尝试获取锁失败");
    }
}


